package com.mijie.homi.service.mood;

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.mijie.core.ApplicationProperties;
import com.mijie.core.RegionInfo;
import com.mijie.exception.RecordNotFoundException;
import com.mijie.homi.common.domain.SearchResult;
import com.mijie.homi.common.domain.mood.Mood;
import com.mijie.homi.common.domain.mood.MoodInfo;
import com.mijie.homi.common.domain.timeline.TimelineEvent;
import com.mijie.homi.common.domain.topic.Topic;
import com.mijie.homi.common.domain.user.User;
import com.mijie.homi.dao.mood.MoodDao;
import com.mijie.homi.dao.mood.MoodInfoDao;
import com.mijie.homi.domain.commom.Review;
import com.mijie.homi.domain.commom.Review.Module;
import com.mijie.homi.domain.mood.MoodStat;
import com.mijie.homi.listener.MoodListener;
import com.mijie.homi.service.common.AbstractEventService;
import com.mijie.homi.service.notify.NotifyUserAgent;
import com.mijie.homi.service.timeline.TimelineService;
import com.mijie.homi.service.topic.TopicService;
import com.mijie.homi.service.user.MoodUserService;
import com.mijie.homi.service.user.SettingService;
import com.mijie.homi.service.user.UserExtInfoService;
import com.mijie.homi.service.user.UserService;
import com.mijie.homi.util.ServerHelper;
import com.mijie.util.GeoUtil;

@Service
public class MoodService extends AbstractEventService{

	@Autowired
	private MoodDao dao;
	@Autowired
	private MoodInfoDao moodInfoDao;
	@Autowired
	private TopicService topicService;
	@Autowired
	private MoodUserService moodUserService;
	@Autowired
	private UserService userService;
	@Autowired
	private UserExtInfoService extInfoService;
	@Autowired
	private MoodListener moodListener;
	@Autowired
	private SettingService settingService;
	@Autowired
	private NotifyUserAgent notifyUserAgent;
	@Autowired
	private TimelineService timelineService;
	
	private Logger logger = Logger.getLogger(MoodService.class);
	
	private Map<Integer,String> moodInfoCache = new HashMap<Integer,String>();
	
	@Override
	public Module getModule() {
		return Review.Module.MOOD;
	}
	
	
	public Mood getMoodById(long id){
		return dao.getMoodById(id);
	}
	
	public int clearMoodContent(long id){
		return dao.clearMoodContent(id);
	}
	
	@Transactional(rollbackFor={Exception.class})
	public int deleteMood(long id,int userId) throws RecordNotFoundException{
		Mood mood = this.getMoodById(id);
		if(mood==null) throw new RecordNotFoundException(id);
		
		int succ =  dao.deleteMood(id,userId);
		if(succ>0){
			moodListener.delete(mood);
		}
		return succ;
	}
	
	public Map<Long,Mood> listMoodMapByIds(List<Long> list){
		return dao.listMoodMapByIds(list);
	}
	
	public Mood getPrevMoodById(int userId,long id){
		return dao.getPrevMoodById(userId,id);
	}
	
	public void applyView(int applicant,Mood mood){
		notifyUserAgent.sendNotifyForMoodViewApply(applicant,mood);
	}
	
	public int acceptViewApply(int applicant,Mood mood){
		int succ = dao.addMoodViewPrivilege(mood.getId(), applicant);
		if(succ>0)
			notifyUserAgent.sendNotifyForAcceptMoodViewApply(applicant,mood);
		return succ;
	}
	
	public void rejectViewApply(int applicant,Mood mood){
		notifyUserAgent.sendNotifyForRejectMoodViewApply(applicant,mood);
	}
	
	public int setVisibility(long id,int userId,int visibility,int allowedToApply){
		return dao.setVisibility(id, userId, visibility, allowedToApply);
	}
	
	public int setBroadcasted(long id){
		return dao.setBroadcasted(id);
	}
	
	public List<MoodInfo> listMoodInfo(){
		return moodInfoDao.listMoodInfo();
	}
	
	@Transactional(rollbackFor={Exception.class})
	public int responseMood(int responder,long id) throws RecordNotFoundException{
		Mood mood = this.getMoodById(id);
		if(mood==null) throw new RecordNotFoundException(id);
		int succ =  dao.addMoodResponder(id, responder);
		if(succ>0){
			dao.responseMood(id);
			notifyUserAgent.sendNotifyForTimelineEventDynamic(mood.getUserId(), TimelineEvent.TYPE_MOOD, id);
		}
		return succ;
	}
	
	@Transactional(rollbackFor={Exception.class})
	public int cancelResponseForMood(int responder,long id){
		int succ =  dao.removeMoodResponder(id, responder);
		if(succ>0){
			dao.cancelResponseForMood(id);
		}
		return succ;
	}
	
	public List<User> listMoodResponder(long moodId,int limit){
		return dao.listMoodResponder(moodId, limit);
	}
	
	public int repostMood(Mood mood){
		long recentyMoodId = dao.getRecentyMoodId(mood.getUserId());
		mood.setId(recentyMoodId);
		mood.setKeyword("");
		if(mood.getContent()!=null && !mood.getContent().trim().isEmpty()){
			String keyword = ServerHelper.getBigramToken(mood.getContent());
			if(keyword.length()>300){
				keyword = keyword.substring(0,keyword.substring(0, 300).lastIndexOf(" "));
			}
			mood.setKeyword(keyword);
		}
		
		boolean containsDisabledWord = ServerHelper.containsDisabledWord(mood.getContent());
		if(containsDisabledWord){
			mood.setContainsDisabledWord(1);
			mood.setContent(ServerHelper.filterSensitiveWord(mood.getContent()));
		}
		
		int rows =  dao.repostMood(mood);
		if(rows>0){
			moodListener.repost(mood);
		}
		return rows;
	}
	
	@Transactional(rollbackFor={Exception.class})
	public int postMood(Mood mood) throws Exception {
		mood.setPublishingAddress("");
		mood.setKeyword("");
		if(ServerHelper.isInternalUser(mood.getUserId())){
			User user = userService.getUserById(mood.getUserId());
			double[] lnglat = GeoUtil.getLocationByAddress(user.getProvince()+user.getCity()+user.getDistrict());
			if(lnglat!=null){
				mood.setLongitude(lnglat[0]);
				mood.setLatitude(lnglat[1]);
			}
		}
		
		
		if(mood.getContent()!=null && !mood.getContent().trim().isEmpty()){
			String keyword = ServerHelper.getBigramToken(mood.getContent());
			if(keyword.length()>300){
				keyword = keyword.substring(0,keyword.substring(0, 300).lastIndexOf(" "));
			}
			mood.setKeyword(keyword);
		}
		
		if(mood.getLatitude()!=0 && mood.getLongitude()!=0){
			extInfoService.updateLocation(mood.getUserId(), mood.getLatitude(), mood.getLongitude(),null);
			RegionInfo region = ApplicationProperties.findRegionInfo(mood.getLatitude(), mood.getLongitude());
			if(region!=null) mood.setPublishingAddress(region.toSimpleAddress());
		}
		
		boolean containsDisabledWord = ServerHelper.containsDisabledWord(mood.getContent());
		if(containsDisabledWord){
			mood.setContainsDisabledWord(1);
			mood.setContent(ServerHelper.filterSensitiveWord(mood.getContent()));
		}
		
		int rows =  dao.postMood(mood);
		if(rows>0){
			TimelineEvent event = new TimelineEvent();
			event.setEventId(mood.getId());
			event.setEventType(TimelineEvent.TYPE_MOOD);
			event.setUserId(mood.getUserId());
			rows = timelineService.addTimelineEvent(event);
			if(rows==0) throw new Exception("Post mood addTimelineEvent fail.");
			rows = dao.setTimelineIdForMood(mood.getId(), event.getId());
			if(rows==0) throw new Exception("Post mood setTimelineIdForMood fail.");
			mood.setTimelineId(event.getId());
			moodListener.post(mood);
		}
		return rows;
	}
	
	@Transactional(rollbackFor={Exception.class})
	public int setTimelineIdForMood(long id,int timelineId){
		return dao.setTimelineIdForMood(id, timelineId);
	}
	
	public List<Mood> listMood(int userId,int offset,int limit){
		return dao.listMood(userId, offset, limit);
	}
	
	public Set<Long> listMoodIdByViewPrivlege(int viewer,List<Long> moodIds){
		List<Long> list =  dao.listMoodIdByViewPrivlege(viewer, moodIds);
		return new HashSet<Long>(list);
	}
	
	public int[] getMateOfMood(int mood){
		return moodInfoDao.getMateOfMood(mood);
	}
	
	public Mood getRecentlyMood(int userId){
		return dao.getRecentlyMood(userId);
	}
	
	public String getMoodNameById(int id){
		String name = moodInfoCache.get(id);
		if(name==null){
			name = moodInfoDao.getMoodNameById(id);
			if(name!=null) moodInfoCache.put(id, name);
		}
		return name;
	}
	
	@Override
	public int getOwner(long eventId) throws RecordNotFoundException{
		Mood mood = this.getMoodById(eventId);
		if(mood == null) throw new RecordNotFoundException(eventId);
		return mood.getUserId();
	}
	
	@Override
	@Transactional(rollbackFor={Exception.class})
	public int increNumOfReview(long id) {
		return dao.increNumOfReview(id);
	}

	@Override
	@Transactional(rollbackFor={Exception.class})
	protected int decreNumOfReview(long id) {
		return dao.decreNumOfReview(id);
	}

	public boolean haveMoodViewPrivilege(int viewer,long id){
		return dao.haveMoodViewPrivilege(viewer, id);
	}
	
	public void makeTopicTagForUser(final int userId,final int mood){
		int offset = 0;
		int limit = 300;
		
		SearchResult searchResult = null;
		Set<String> tags = new HashSet<String>();
		String[] keys = null;
		Topic topic = null;
		while(true){
			try {
				searchResult = topicService.listTopicOfMoodMatch("", mood, offset, limit);
				offset+=limit;
			} catch (Exception e) {
				searchResult = null;
				logger.error(e.getMessage(), e);
			}
			if(searchResult==null) break;
			JSONObject json = null;
			JSONArray list = searchResult.getResult();
			if(list.isEmpty()) break;
			for(int i=0;i<list.size();i++){
				json = list.getJSONObject(i);
				topic = topicService.getTopicById(json.getInt("id"));
				if(topic==null) continue;
				keys = topic.getTag().split(",")[0].split(" ");
				if(keys!=null && keys.length>0){
					for(String key : keys){
						if(!key.trim().isEmpty())
							tags.add(key);
					}
				}
			}
			if(tags.size()>=200) break;
		}
		logger.info("###makeTopicTagForUser["+userId+"] mood["+mood+"],tags size:"+tags.size());
		if(!tags.isEmpty()){
			JSONArray array = JSONArray.fromObject(tags);
			topicService.addTopicTagForUser(userId, array.toString());
			array.clear();
			array = null;
		}else{
			topicService.addTopicTagForUser(userId, "[]");
		}
	}
	
	public MoodStat getMoodStatByUserId(int userId){
		return dao.getMoodStatByUserId(userId);
	}
	
	public List<Mood> listTodayMood(int userId){
		return dao.listTodayMood(userId);
	}
}
